<?php
/**
 * User: lufei
 * Date: 2020/1/13
 * Email: lufei@swoole.com
 */

namespace App\Task;

use App\Game\Conf\GameProgress;
use App\Game\Core\Djs;
use App\Game\Core\Robot;
use App\Game\Core\Room;
use App\Game\Timer\GameTimer;
use App\Model\User;
use Hyperf\Logger\Logger;
use Hyperf\Task\Annotation\Task;
use App\Game\Core\Packet;
use App\Game\Conf\MainCmd;
use App\Game\Conf\SubCmd;
use App\Game\Core\MJ;
use Hyperf\Utils\Context;
use Psr\Container\ContainerInterface;
use Swoole\WebSocket\Server as WebSocketServer;

class GameSyncTask
{

    /**
     * @var \Psr\Log\LoggerInterface
     */
    protected $logger;

    /**
     * @var ContainerInterface
     */
    private $container;

    public function __construct(ContainerInterface $container)
    {
        $this->container = $container;
    }

    /**
     * 发牌
     * @param $room_no
     */
    public function assignCards(int $room_no, int $master): void
    {
        $game_conf = config('game');
        $user_conf = config('user');
        $robot_conf = config('robot');
        $serv = server();
        $room_chair_key = sprintf($game_conf['user_room_chair'], $room_no);
        $user_chair = json_decode(redis()->get($room_chair_key), true);
        $players = getGamePrepareALL($room_no);
        if (count($players) < 4) {
            $waiters = getRoomWait($room_no);
            if (count($waiters) != 4) { //房间用户信息错误的时候，踢出所有用户
                foreach ($waiters as $acc) {
                    pushForceQuitMsg($room_no, $acc);
                    sleep(2);
                }
                return;
            }
            $players = [];
            foreach ($waiters as $acc) {
                if ($acc) {
                    $players[$acc] = 1;
                }
            }
            if (count($players) < 4) {  //房间用户信息错误的时候，踢出所有用户
                foreach ($players as $acc => $v) {
                    pushForceQuitMsg($room_no, $acc);
                    sleep(2);
                }
                return;
            }
        }
        switch ($master) {
            case 2:
                $order = [2, 3, 4, 1];
                break;
            case 3:
                $order = [3, 4, 1, 2];
                break;
            case 4:
                $order = [4, 1, 2, 3];
                break;
            default:
                $order = [1, 2, 3, 4];
        }

        // 出牌顺序
        $call_order[] = array_search($order[0], $user_chair);
        $call_order[] = array_search($order[1], $user_chair);
        $call_order[] = array_search($order[2], $user_chair);
        $call_order[] = array_search($order[3], $user_chair);

        $users = $fds = array();
        foreach ($players as $account => $v) {
            $users[] = $account;
            $fds[$account] = getFdByAccount($room_no, $account);
        }
        if (!empty($call_order)) {
            $users = $call_order;
        }

        $obj = new MJ();
        $cards = $obj->dealCards($users);//随机发牌
        //dd('dealCards', $cards);
        //庄家多拿一张牌出来
        $hand = $cards['card']['hand'];
        $masterCardArr = array_splice($hand, 0, 1);
        $masterCard = $masterCardArr[0];

        //dd('masterCard', $masterCard);

        $game_type = Room::getRoomData($room_no, 'game_type');
        dd('game_type', $game_type);
        if ($game_type == 1) {
            $waiters = Room::getRoomWait($room_no);
            foreach ($waiters as $acc) {
                if (Robot::isRobot($room_no, $acc)) {
                    continue;
                }
                $playerInfo = Djs::getDjsPlayerData($acc);
                $playerInfo['progress'] = Djs::$progress_game_start;
                Djs::updatePlayerData($acc, $playerInfo);
            }
        }

        //存入牌局数据信息,房号，底手牌
        $room_data = array(
            'room_no' => $room_no,
            'hand' => $hand,   //底牌
            'master' => $master,  //庄家座椅号
            'is_game_over' => 0,
            'game_type' => intval($game_type), //游戏类型 0.普通游戏 1.大奖赛
        );

        foreach ($users as $k => $v) {
            $cardArr = $cards['card'][$v];
//            ddNode('f1');
            $is_robot = Robot::isRobot($room_no, $v);
            if ($is_robot) {
//                ddNode('f2');
                $total_score = (int)Robot::getRoomRobot($room_no, $v);
            } else {
//                ddNode('f3');
                $uinfo = User::userInfo($v);
                $total_score = $uinfo['score'];
            }
//            dd('total_score', $total_score);
            $room_data['uinfo'][$v] = ['chair_id' => $user_chair[$v], 'score' => 0,
                'total_score' => $total_score];
            //dd('user_chair[v]', $user_chair[$v]);
            if ($user_chair[$v] == $master) { //庄家多拿一张牌
                $cardArr[] = $masterCard;
                sort($cardArr);
            }
            $room_data[$v] = [
                'card' => $cardArr,
                'chair_id' => $user_chair[$v],
                'peng' => [],
                'gang' => [],
                'hu' => [],
                'hu_detail' => [],
                'out_card' => [],
                'is_robot' => (in_array($v, $robot_conf['robots'])) ? 1 : 0,
                'take_over' => 0
            ];
        }

        Room::updateRoomData($room_no, $room_data);
//        $user_room_data_key = sprintf($game_conf['user_room_data'], $room_no);
//        arrToHashInRedis($room_data, $user_room_data_key);

        //更新游戏进度为换牌
        setGameProgress($room_no, GameProgress::GAME_CHANGE_CARD);
        resetOperCounter($room_no);

//        dd('assign_card_users', $users);

        //分别发牌给四个人
        foreach ($users as $k => $v) {
            $fd = getFdByAccount($v);
//            ddTitle('assign_card to ' . $v);
//            dd('card', $room_data[$v]);
            $data = Packet::packFormat('OK', 1, $room_data[$v]);
            $data = Packet::packEncode($data, MainCmd::CMD_SYS, SubCmd::SUB_GAME_JOIN_RESP);
            $plstatus = playerStatus($room_no, $v);
            if ($plstatus == GameProgress::USER_ONLINE) { //玩家在线才能发送消息
                $serv->push($fd, $data, WEBSOCKET_OPCODE_BINARY);
            }
        }
        //延时5秒异步广播通知换牌
        delayBroadCast(5, $room_no, ['wait_time' => $user_conf['change_timer']],
            SubCmd::SUB_GAME_START_HUAN_PAI, GameTimer::$CHANGE_CARD_TIMER);
    }

    /**
     * 换牌
     * @param $room_no
     */
    public function changeCards(int $room_no): void
    {
        $game_conf = config('game');
        $user_conf = config('user');
        $serv = server();
        $room_change_key = sprintf($game_conf['user_room_change'], $room_no);
        $user_changes = json_decode(redis()->get($room_change_key), true);
        $room_chair_key = sprintf($game_conf['user_room_chair'], $room_no);
        $room_data_key = sprintf($game_conf['user_room_data'], $room_no);
        $room_data = redis()->hGetAll($room_data_key);
        $user_chairs = json_decode(redis()->get($room_chair_key), true);
        //user_room_change => [$uid1=>[1,2,3],$uid2=>[11,12,13],$uid3=>[21,22,23],
        //[user_room_chair] => [uid1=>1,uid2=>2,uid3=>3,uid4=
        $changeArr = [];
        foreach ($user_changes as $v) {
            foreach ($v as $k => $m) {
                $changeArr[$k] = $m;
            }
        }
        dd('room_data', $room_data);
        dd('user_chairs', $user_chairs);
        dd('changeArr', $changeArr);
        $user_room_data = $room_data;
        foreach ($user_chairs as $k => $v) {
            switch ($v) {
                case 1:
                    $charNo = 4;
                    break;
                case 2:
                    $charNo = 3;
                    break;
                case 3:
                    $charNo = 2;
                    break;
                case 4:
                    $charNo = 1;
                    break;
            }
            $changeCard = [];
            foreach ($user_chairs as $m) {
                if ($m == $charNo) {
                    $changeCard = $changeArr[$m];
                }
            }
            //拿到玩家手牌
            $user_data = json_decode($room_data[$k], true);
            dd('user_data_befor', $user_data);
            dd('charNo', $charNo);
            dd('k', $v);
            dd('changeCard', $changeCard);
            //去掉选出的换牌
            foreach ($changeArr[$v] as $m) {
                foreach ($user_data['card'] as $n => $p) {
                    if ($m == $p) {
                        unset($user_data['card'][$n]);
                        break;
                    }
                }
            }
            sort($user_data['card']);
            $user_rest_cards = $user_data['card'];
            dd('user_rest_cards', $user_rest_cards);
            //加入其他玩家的换牌
            $user_cards = array_merge($user_rest_cards, $changeCard);
            sort($user_cards);
            $user_data['card'] = $user_cards;
            //更新房间玩家手牌数据
            $room_data[$k] = $user_data;
            dd('room_data', $room_data);
        }
        dd('room_data', $room_data);
        $this->arrToHashInRedis($room_data, $room_data_key);

        $fds = [];
        //分别发消息给四个人
        foreach ($user_chairs as $k => $v) {
            $key = sprintf($game_conf['user_bind_key'], $k);
            //根据账号获取fd
            $fd = redis()->get($key);
            if (isset($fd)) {
                $fds[] = $fd;
                $returnData = $room_data[$k];
                if (gettype($returnData) == 'string') {
                    $returnData = json_decode($returnData, true);
                }
                dd('k', $k);
                dd('returnData', $returnData);
                $data = Packet::packFormat('OK', 1, $returnData);
                $data = Packet::packEncode($data, MainCmd::CMD_SYS, SubCmd::SUB_GAME_CHANGE_OVER_RESP);
                $client_info = $serv->getClientInfo($fd);
                $client[$fd] = $client_info;
                if (isset($client_info['websocket_status']) && $client_info['websocket_status'] == 3) {
                    $serv->push($fd, $data, WEBSOCKET_OPCODE_BINARY);
                }
            }
        }
        sleep(3);
        //开始推送定缺
        //分别发消息给四个人
        foreach ($fds as $v) {
            $data = Packet::packFormat('OK', 1, ['wait_time' => $user_conf['choose_timer']]);
            $data = Packet::packEncode($data, MainCmd::CMD_SYS, SubCmd::SUB_GAME_START_CHOOSE_COLOR);
            $serv->push($v, $data, WEBSOCKET_OPCODE_BINARY);
        }

    }

    /**
     * 定缺
     * @param $room_no
     */
    public function chooseColor(int $room_no): void
    {
        $game_conf = config('game');
        $user_conf = config('user');
        $serv = server();
        $room_color_key = sprintf($game_conf['user_room_color'], $room_no);
        $user_colors = json_decode(redis()->get($room_color_key), true);
        $room_chair_key = sprintf($game_conf['user_room_chair'], $room_no);
        $chair_data = json_decode(redis()->get($room_chair_key), true);
        $colorsArr = [];
        foreach ($user_colors as $v) {
            foreach ($v as $k => $m) {
                $colorsArr[$k] = $m;
            }
        }
        $colorData = [];
//        dd('user_colors', $user_colors);
//        dd('chair_data', $chair_data);
        foreach ($colorsArr as $k => $v) {
            $chire_id = $chair_data[$k];
            $colorData[] = ['chair_id' => $chire_id, 'que' => $v];
        }
        $data = Packet::packFormat('OK', 1, ['colors' => $colorData]);
        $return_data = Packet::packEncode($data, MainCmd::CMD_SYS, SubCmd::SUB_GAME_CHOOSE_OVER_RESP);
        //分别发消息给四个人
        $fds = $this->getOtherFdsByRoomNo($room_no);// 当前房间所有连接
        foreach ($fds as $fd) {
            //获取客户端信息
            $client_info = $serv->getClientInfo($fd);
            $client[$fd] = $client_info;
            if (isset($client_info['websocket_status']) && $client_info['websocket_status'] == 3) {
                $serv->push($fd, $return_data, WEBSOCKET_OPCODE_BINARY);
            }
        }
        sleep(3);
        //发送出牌消息

        $room_data_key = sprintf($game_conf['user_room_data'], $room_no);
        dd('room_data_key', $room_data_key);
        $room_data = redis()->hGetAll($room_data_key);
        dd('room_data', $room_data);
        $master = $room_data['master'];
        $this->updateRoomData($room_no, ['next_chair_id' => $master]);
        $data = Packet::packFormat('OK', 1, ["next_chair_id" => $master,
            "wait_time" => $user_conf['play_timer']]);
        $return_data = Packet::packEncode($data, MainCmd::CMD_SYS, SubCmd::SUB_GAME_OUT_CARD);
        foreach ($fds as $fd) {
            //获取客户端信息
            $client_info = $serv->getClientInfo($fd);
            $client[$fd] = $client_info;
            if (isset($client_info['websocket_status']) && $client_info['websocket_status'] == 3) {
                $serv->push($fd, $return_data, WEBSOCKET_OPCODE_BINARY);
            }
        }
    }


    /**计时器序号
     * @param $room_no
     * @return int
     */
    protected function getTradeTimes($room_no)
    {
        $game_conf = config('game');
        $user_room_tradeTimes = sprintf($game_conf['user_room_trade_times'], $room_no);
        if (redis()->exists($user_room_tradeTimes)) {
            $times = redis()->get($user_room_tradeTimes);
        } else {
            redis()->set($user_room_tradeTimes, 1);
            $times = 1;
        }
        return (int)$times;
    }

    /**
     * 获取房间其他用户的fds
     * @param $room_no
     * @param $account
     * @return array
     */
    protected function getOtherFdsByRoomNo($room_no)
    {
        $game_conf = config('game');
        $room_wait_key = sprintf($game_conf['user_room_wait'], $room_no);
//        dd('room_no', $room_no);
//        dd('room_wait_key', $room_wait_key);
        $room_users = redis()->get($room_wait_key);
//        dd('room_users', $room_users);
        $room_users = json_decode($room_users, true);
//        dd('decode_room_users', $room_users);
        $fds = [];
        foreach ($room_users as $k => $v) {
            $bind_key = sprintf($game_conf['user_bind_key'], $v);
            $fds[] = redis()->get($bind_key);
        }
        return $fds;
    }

    /**
     * 批量更新房间数据
     * @param $room_no
     * @param $params
     */
    protected function updateRoomData($room_no, $params)
    {
        $game_conf = config('game');
        $room_data_key = sprintf($game_conf['user_room_data'], $room_no);
        if (redis()->exists($room_data_key)) {
            foreach ($params as $key => $val) {
                redis()->hSet($room_data_key, (string)$key, $val);
            }
        }
    }
}